# Go语言方法
# 1 方法的定义
Go语言中的方法(
Method
)是一种作用于特定类型变量的函数。方法是与对象实例绑定的特殊函数。 这种特定类型变量叫做接收者(Receiver
)。接收者的概念就类似于其他语言中的this
或者self
。
方法定义语法
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
//方法体
}
2
3
- 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是self、this之类的命名。
- 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
- 方法名、参数列表、返回参数:具体格式与函数定义相同。
举例如下
package main
import "fmt"
type student struct {
name string
age int
}
type dog struct {
name string
}
func (s *student) say(){
fmt.Printf("%s向大家问好\n", s.name)
}
func main() {
//声明一个变量stu
var stu student
//变量赋值
stu.name="福小林"
//调用student类型特定的方法say()
stu.say()
/* var d dog
d.name="牧羊犬"
//此处不能调用say(),报错d.say undefined (type dog has no field or method say)
d.say() */
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 1.1 指针类型的接收者
指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。这种方式就十分接近于其他语言中面向对象中的this或者self。 例如我们为Person添加一个SetAge方法,来修改实例变量的年龄。
//定义一个student的结构体
type student struct {
name string
age int
}
func (s *student) say(){
s.age++
}
func main() {
//声明一个变量stu
var stu student
//变量赋值
stu.name="张三"
stu.age=18
fmt.Printf("调用say()方法之前%s的年龄%d\n",stu.name,stu.age) //18
//调用student类型特定的方法say()
stu.say()
fmt.Printf("调用say()方法后%s的年龄%d\n",stu.name,stu.age) //19
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1.2 值类型的接收者
当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。
type student struct {
name string
age int
}
func (s student) say(){
s.age++
}
func main() {
//声明一个变量stu
var stu student
//变量赋值
stu.name="李四"
stu.age=30
fmt.Printf("调用say()方法之前%s的年龄%d\n",stu.name,stu.age) //30
//调用student类型特定的方法say()
stu.say()
fmt.Printf("调用say()方法后%s的年龄%d\n",stu.name,stu.age) //30
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1.3 什么时候使用指针类型接收者
- 需要修改接收者中的值
- 接收者是拷贝代价比较大的大对象
- 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。
# 2 为什么有函数了还需要方法呢
原因
- Go不是纯粹的面向对象编程语言,而且Go不支持类.因此基于类型的方法是一种实现和类相似行为的途径
- 相同的名字的方法可以定义在不同的类型上,而相同名字的函数是不被允许的。
# 3 任意类型添加方法
在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法
//MyInt 将int定义为自定义MyInt类型
type MyInt int
//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
fmt.Println("Hello, 我是一个int。")
}
func main() {
var m1 MyInt
m1.SayHello() //Hello, 我是一个int。
m1 = 100
fmt.Printf("%#v %T\n", m1, m1) //100 main.MyInt
}
2
3
4
5
6
7
8
9
10
11
12
13
注意:非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。
# 4 结构体的“继承”
Go语言中使用结构体也可以模拟实现其他编程语言中面向对象的继承。
package main
import "fmt"
//Animal 动物
type Animal struct {
name string
}
func (a Animal) move() {
fmt.Printf("%s会动!\n", a.name)
}
//Dog 狗 Dog包裹了Animal 模拟继承了Animal
type Dog struct {
Feet int8
Animal //Animal拥有的方法,Dog也拥有了,因为Dog包裹了Animal,通过嵌套匿名结构体模拟实现继承
}
func (d Dog) wang() {
fmt.Printf("%s会汪汪汪~\n", d.name) // d.name相当于 d.Animal.name
}
func main() {
d1 := Dog{
Feet: 4,
Animal: Animal{
name: "旺财",
},
}
d1.wang() //旺财会汪汪汪~
d1.move() //旺财会动!
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 函数和方法的区别
函数和方法的区别
1、普通函数:接收者(函数参数)为值类型时,不能将指针类型的数据直接传递,反之亦然。
func function_name([parameter list]) [return_types] {
/*函数体*/
}
2
3
2、方法(如struct方法): 接收者为值类型时,可以直接用指针类型的变量调用方法,反之亦然。
func (variable_name variable_data_type) function_name() [return_type]{
/* 方法体*/
}
2
3
TIP
方法与函数的区别是,函数不属于任何类型,方法属于特定的类型
方法是与对象实例绑定的特殊函数。
用于维护和展示对象自身的状态。对象是内敛的。普通函数则专注与算法流程,通过接受参数来完成特定的逻辑运算,并返回最终结果,方法是有关联状态的,函数通常是没有的。
方法和函数定义语法区别在于前者实例接受参数,编译器以此确定方法所属的类型。在一些语言中尽管没有定义,但是函数使用了隐式的传递this实例参数。